5. Event Handling
One of the most frequently used features of JavaScript is
event handling, whether we define it inside the HTML document or by
using code. Let’s see how mobile browsers work with this way to execute
script code.
5.1. Managing events
We can define event handling in scripts using the following
methods, browser support for which is listed in Table 22:
Using HTML attributes, like onclick="alert('sample')"
Using the JavaScript object property, element.onclick = function() {}
Using the DOM addEventListener method
Note:
Microsoft uses the attachEvent property of the element
instead of the DOM addEventListener method in Internet
Explorer.
Table 22. Event registration compatibility table
Browser/platform | HTML
attribute | Object
property | addEventListener |
---|
Safari | Yes | Yes | Yes |
Android
browser | Yes | Yes | Yes |
Symbian/S60 | Yes | Yes | Yes |
Nokia Series
40 | Yes | No before
4.6 | No before
4.6 |
webOS | Yes | Yes | Yes |
BlackBerry | Yes | No before
4.6 | No |
NetFront | Yes | Yes | No |
Internet
Explorer | Yes | No | No |
Motorola Internet
Browser | Yes | No | No |
Opera
Mobile | Yes | Yes | Yes |
Opera
Mini | Yes, with server
postback |
5.2. Load and unload events
The famous onload
event is available for any HTML element, but it is best used in the
body element. We’ll test
compatibility over different types of elements.
The onunload event is less
famous. In theory it should work for every element, but again the most
useful usage is applied to the body
element (document object) to detect
when the user is navigating away from our document.
In modern browsers, the onunload event does not work as we might
want (I remember many battles against the onunload event when a new pop-up was opened
every time I closed one), and it has been replaced by the nonstandard
onbeforeunload. The onbeforeunload event is useful for
alerting the user about unfinished work so she doesn’t lose any
changes she’s made on the page before going back or browsing to
another URL. To do this, it is generally used with a confirm
dialog.
Table 23
reports on the compatibility of all of these events across
browsers.
Table 23. Load events compatibility table
Browser/platform | body
(load) | body
(unload) | body
(beforeunload) | img
(load) |
---|
Safari | Yes | Yes | No | Yes |
Android
browser | Yes | Yes | Yes | Yes |
Symbian/S60 | Yes | Yes | No | Yes |
Nokia Series
40 | Yes | No | No | No before
6th edition |
webOS | Yes | Yes | Yes | Yes |
BlackBerry | Yes | No | No | Yes |
NetFront | Yes | Yes | No | Yes |
Internet
Explorer | Yes | Yes | No | Yes |
Motorola Internet
Browser | No | No | No | No |
Opera
Mobile | Yes | No | No | Yes |
Opera
Mini | Yes | No | No | No |
5.3. Click events
The onclick event is
the most-used event on the Web. In mobile sites, we have to test it to
see where it can best be used. We know that there are focus-based,
touch-based, and cursor-based browsers. The last ones are the simplest
for click events: every time the user moves the cursor arrow and then
presses FIRE or any other similar key, an onclick event is generated. In focus-based
browsers, it is recommended to use the onclick event only in clickable elements,
such as links or buttons, because the focus will not be active on
other elements (such as div,
p, or li elements).
Warning:
The input type button should be used with care when developing
for low-end devices. Some Series 40 devices require a form tag for every input to be rendered,
and some Motorola devices use these buttons as submit buttons, so
pressing them causes the form to be submitted.
For touch devices, the behavior is simple, too: every touch
(finger- or stylus-based) is transferred as a click over the screen.
Table 24
reports on how different devices support these events.
Table 24. Click event compatibility table
Browser/platform | a | img | div | li |
---|
Safari | Yes | Yes | Yes | Yes |
Android
browser | Yes | Yes | Yes | Yes |
Symbian/S60 | Yes on touch and cursor
browsing |
Nokia Series
40 | No before 6th
edition |
webOS | Yes | Yes | Yes | Yes |
BlackBerry | Yes | No | No before
4.6 | No |
NetFront | Yes | Yes | Yes | Yes |
Internet
Explorer | No | No | No | Yes |
Motorola Internet
Browser | Yes, they are all converted to
buttons |
Opera
Mobile | Yes | Yes | Yes | Yes |
Opera
Mini | Yes | Yes | Yes | Yes |
Warning:
If the user is using a finger to touch the screen, you need to
be aware that the click coordinates can change during the touch
(depending on how the user presses the screen), and the precision
will not be good. Use big areas as clickable ones.
5.3.1. Double tap
On touch devices, if you want to detect a double-tap
gesture, you shouldn’t use the nonstandard ondblclick event; in most cases it will
not work and it will also fire an onclick. The best solution (also
compatible with non-touch devices) is to implement a tap–double tap
detection pattern using the following code sample:
var doubletapDeltaTime_ = 700;
var doubletap1Function_ = null;
var doubletap2Function_ = null;
var doubletapTimer = null;
function tap(singleTapFunc, doubleTapFunc) {
if (doubletapTimer==null) {
// First tap, we wait X ms to the second tap
doubletapTimer_ = setTimeout(doubletapTimeout_, doubletapDeltaTime_);
doubletap1Function_ = singleTapFunc;
doubletap2Function_ = doubleTapFunc;
} else {
// Second tap
clearTimeout(doubletapTimer);
doubletapTimer_ = null;
doubletap2Function_();
}
}
function doubletapTimeout() {
// Wait for second tap timeout
doubletap1Function_();
doubleTapTimer_ = null;
}
We can use the previous library like this:<img src="bigbutton.png" onclick="tap(tapOnce, tapTwice)" />
supposing tapOnce and
tapTwice are two previously
declared global functions.
Note:
In general, in a nonclickable element no events will be
generated, while in clickable elements events are fired in the
order onmouseover, onmousedown, onmouseup, onclick.
Alternatively, we can use it from JavaScript as
follows:
element.onclick = function() {
tap(
function() {
// This is the code for the first tap
},
function() {
// This is the code for the second tap
}
);
}
Note:
Remember that implementing touch and hold (or long press)
handling can cause problems in some touch browsers because the
browser is already capturing this event for contextual menus. You
can only apply it in text blocks with user-selectable disabled.
5.3.2. Touch and multitouch events
Safari as of iOS 2.0 has multitouch support. The user
can touch the screen with up to five fingers at the same time (11
fingers on the iPad) and the JavaScript code will receive the event
for this. For multitouch detection, we should not use the standard
onclick event. Instead, we should
replace it with the following nonstandard events:
ontouchstart
ontouchmove
ontouchend
ontouchcancel
Note:
The Android browser also supports these touch
events, but the multitouch support depends on the hardware and
software implementation.
When we capture these events, we will receive them both for
single touches and multitouches. Every time the user presses a
finger on the screen, ontouchstart will be executed; if she
moves one or more fingers, ontouchmove will be the event to capture;
and when the user removes her fingers, ontouchend will be fired. What about
ontouchcancel? A touch cancel
event is executed if any external event with more priority than our
website (e.g., an alert window, an incoming call, or a push
notification) cancels the operation.
Warning:
If you are creating a game, a drawing application, or some
other solution capturing touches, it is very important to remember
the ontouchcancel event and to
pause or stop the touch behavior when this event fires.
The four multitouch events receive the same event object
(TouchEvent) as a parameter. It
contains a touches array
representing the coordinates of each touch on the page; each array
element is an object with pageX
and pageY properties. If the
device is not multitouch-enabled, you will receive an array of only
one element.
A typical scenario, then, will be:
<div
ontouchstart="touchStart(event);"
ontouchmove="touchMove(event);"
ontouchend="touchEnd(event);"
ontouchcancel="touchCancel(event);">
</div>
Note:
A touch sequence begins with the first finger and ends with
the last finger. The touch events will be delivered to the same
object that received the ontouchstart, no matter where the
current touches are located.
The first thing we may want to do in all events is to cancel
the default behavior of Safari for the gesture the user is doing.
This can be done with the TouchEvent parameter:
event.preventDefault();
The TouchEvent object
supports the array collections shown in Table 25.
Table 25. TouchEvent collections
TouchEvent
attribute | Description |
---|
touches | All the touches
actually on the screen |
targetTouches | Only the touches
inside the target element of the event |
changedTouches | Only the touches that
changed since the last event call (useful in ontouchmove and ontouchend or to filter only new
or removed touches) |
When the user lifts a finger from the screen, that touch will
be available in changedTouches but not in the
other collections. In Android, the removed touch is also available
in the touches collection.
Every Touch object has the
properties outlined in Table 26.
Table 26. Properties of the Touch object
Touch
attribute | Description |
---|
clientX, clientY | Touch coordinates
relative to the viewport |
screenX, screenY | Touch coordinates
relative to the screen |
pageX, pageY | Touch coordinates
relative to the whole page, including the scroll
position |
identifier | A number for
identifying the touch between event calls |
target | The original HTML
element where the event was originated |
The following sample will show a blue 20px circle below each
finger touching the screen:
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
"http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>iPhone Multitouch</title>
<meta name="viewport" content="width=device-width; initial-scale=1.0;
maximum-scale=1.0; user-scalable=0;">
<style type="text/css">
.point {
width: 20px;
height: 20px;
position: absolute;
-webkit-border-radius: 10px;
background-color: blue;
}
</style>
<script type="text/javascript">
function touch(event) {
event.preventDefault();
for (var i=0; i<event.touches.length; i++) {
var top = event.touches[i].pageY-10;
var left = event.touches[i].pageX-10;
var html = "<div class='point' style='left: " + left +
"px ; top: " + top + "px'></div>";
document.getElementById("container").innerHTML += html;
}
}
function clean() {
document.getElementById("container").innerHTML = "";
}
</script>
</head>
<body>
<div ontouchstart="touch(event)" ontouchend="clean()" id="container"
style="background-color:red; width: 300px; height: 300px">
</div>
</body>
</html>